package com.sykj.util;

import com.sykj.bean.bis.BisNurseBag;
import com.sykj.bean.card.BisNurseBagDto;
import com.sykj.bean.card.CardGame;
import com.sykj.bean.card.CardGameProduct;
import com.sykj.mapper.GameLoadMapper;
import com.sykj.service.CardGameProductService;
import com.sykj.service.CardGameService;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @program: hongbao
 * @description:
 * @author: qiaoli
 * @create: 2020-08-05 10:49
 */
public class DateTimeJob extends QuartzJobBean {
    private final static Logger log = LoggerFactory.getLogger(DateTimeJob.class);
    @Autowired
    CardGameService cardGameService;
    @Autowired
    RedisByhUtils redisByhUtils;
    @Autowired
    GameLoadMapper gameLoadMapper;
    @Autowired
    CardGameProductService cardGameProductService;
    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        //获取JobDetail中关联的数据
        String msg = (String) jobExecutionContext.getJobDetail().getJobDataMap().get("msg");
        System.out.println("current time :"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "---" + msg);
        //创建一个当前时间
        Date now =new Date();
        //查询将来一分钟内要开始的活动
        List<CardGame> cardGames = cardGameService.selectByExample(now);
              // 判断是否有活动
        if(cardGames.size()== 0){
            //没有查询到要开始的活动
            log.info("game list scan : size = 0");
            return;
        }
        log.info("game list scan : size = {}",cardGames.size());

        // 有关活动数据 将进行活动数据预热，并存入 redis中
        cardGames.forEach(game -> {
            // 活动的开始时间 戳
            long start =game.getStarttime().getTime();
            //活动的结束时间戳
            long end= game.getEndtime().getTime();
            //在计算活动结束时间和现在时间相差多少秒 ，并将其作做为 redis key 的过期时间
             //得到的是毫秒值，将其除以1000得到秒
            long expire = (end-now.getTime())/1000;

            //活动总共持续时间(毫秒值)
            long  duration =end-start;
            //活动的基本信息
             //将活动的状态修改为开始
//            game.setStatus(1);
            //并把活动的信息存入到redis中
            redisByhUtils.set(RedisKeys.INFO+game.getId(),game,-1);
            log.info("load game info:{},{},{},{}", game.getId(),game.getTitle(),game.getStarttime(),game.getEndtime());

            // 活动奖品信息
            List<BisNurseBagDto> products=gameLoadMapper.getByGameId(game.getId().toString());
            Map<String, BisNurseBag> productMap=new HashMap<>(products.size());
            products.forEach(p -> productMap.put(p.getBagId(),p));
            log.info("load product type:{}",productMap.size());
            // 奖品数量配置信息
            List<CardGameProduct> gameProducts = cardGameProductService.selectByExample(game.getId());

            log.info("load bind product:{}",gameProducts.size());

             // 生成令牌桶
            List<Long>  tokenList=new ArrayList<>();
            gameProducts.forEach(cgp -> {
                //生成一个amount 个 start到end 之间的随机数时间戳做令牌
                for (int i=0 ; i< cgp.getAmount(); i++){
                    long rnd = start+ new Random().nextInt(((int) duration));
                    // 将生成的token乘于100 加随机数 是为了 防止时间段奖品多时重复
                    // 在取令牌判断时间时要 在  除以 1000 ，以还原真正的事件戳
                    long  token= rnd *1000+new Random().nextInt(999);
                    // 将令牌放到令牌桶中
                    tokenList.add(token);

                    //以令牌做key，对应的商品为value，创建redis缓存
                    log.info("token -> game : {} -> {}",token/1000 ,productMap.get(cgp.getProductid()+"").getBagName());
                   redisByhUtils.set(RedisKeys.TOKEN+game.getId()+"_"+token,productMap.get(cgp.getProductid()+""),expire);
                }
            });
            // 将令牌 排序后在放入 reids队列中
             Collections.sort(tokenList);
            log.info("load tokens:{}",tokenList);
            //然后在从右侧压入队列中, 从左到右 时间戳达到逐个增大;
            redisByhUtils.rightPushAll(RedisKeys.TOKENS+game.getId(),tokenList);
            // 在设置token的过期时间
            redisByhUtils.expire(RedisKeys.TOKENS + game.getId(),expire);

              // 奖品的策略配置信息，因没有会员等级制度， 这里不需要策略信息，
            // 在将来可作为扩展
//            List<CardGameRules> rules = gameRulesMapper.selectByExample(rulesExample);
//            //遍历策略，存入redis hset
//            rules.forEach(r -> {
//                redisUtil.hset(RedisKeys.MAXGOAL +game.getId(),r.getUserlevel()+"",r.getGoalTimes());
//                redisUtil.hset(RedisKeys.MAXENTER +game.getId(),r.getUserlevel()+"",r.getEnterTimes());
//                log.info("load rules:level={},enter={},goal={}",r.getUserlevel(),r.getEnterTimes(),r.getGoalTimes());
//            });
//            redisUtil.expire(RedisKeys.MAXGOAL +game.getId(),expire);
//            redisUtil.expire(RedisKeys.MAXENTER +game.getId(),expire);


            // 活动状态要更改为已预热状态， 并禁止管理后台在随便更改变动
            game.setStatus(1);
            cardGameService.updateByPrimaryKey(game);
        });
    }
}
